#include "aodv_rreq.h"
#include "aodv_packet.h"
#include "aodv_socket.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 全局 RREQ ID 计数器
static uint32_t g_rreq_id_counter = 0;

// 初始化 RREQ ID 缓存
void rreq_id_cache_init(rreq_id_cache *cache) {
    if (cache == NULL) return;
    memset(cache->entries, 0, sizeof(cache->entries));
    cache->count = 0;
}

// 检查 RREQ ID 是否已存在
int rreq_id_cache_contains(rreq_id_cache *cache, uint32_t orig_addr, uint32_t rreq_id) {
    if (cache == NULL) return 0;
    
    uint32_t current_time = (uint32_t)time(NULL);
    
    for (int i = 0; i < cache->count; i++) {
        // 检查是否匹配且未过期（假设缓存条目有效期为 10 秒）
        if (cache->entries[i].orig_addr == orig_addr && 
            cache->entries[i].rreq_id == rreq_id &&
            (current_time - cache->entries[i].timestamp) < 10) {
            return 1; // 找到匹配项
        }
    }
    return 0; // 未找到
}

// 添加 RREQ ID 到缓存
void rreq_id_cache_add(rreq_id_cache *cache, uint32_t orig_addr, uint32_t rreq_id) {
    if (cache == NULL) return;
    
    uint32_t current_time = (uint32_t)time(NULL);
    
    // 如果缓存已满，移除最旧的条目
    if (cache->count >= RREQ_ID_CACHE_SIZE) {
        // 简单的 FIFO 策略：移除第一个条目
        for (int i = 0; i < cache->count - 1; i++) {
            cache->entries[i] = cache->entries[i + 1];
        }
        cache->count--;
    }
    
    // 添加新条目
    cache->entries[cache->count].orig_addr = orig_addr;
    cache->entries[cache->count].rreq_id = rreq_id;
    cache->entries[cache->count].timestamp = current_time;
    cache->count++;
}

// 生成新的 RREQ ID
uint32_t generate_rreq_id(void) {
    return ++g_rreq_id_counter;
}

// 检查是否需要转发 RREQ
int should_forward_rreq(const aodv_rreq *rreq, uint32_t local_ip, 
                       aodv_routing_table *routing_table, rreq_id_cache *rreq_cache) {
    if (rreq == NULL || routing_table == NULL || rreq_cache == NULL) return 0;
    
    // 1. 如果当前节点是目标节点，不转发
    if (rreq->dest_addr == local_ip) {
        return 0;
    }
    
    // 2. 检查 RREQ 是否已经被处理过
    if (rreq_id_cache_contains(rreq_cache, rreq->orig_addr, rreq->rreq_id)) {
        return 0; // 已经处理过，不转发
    }
    
    // 3. 检查是否有到目标节点的有效路由且序列号足够新
    routing_table_entry *route_entry = routing_table_find(routing_table, rreq->dest_addr);
    if (route_entry != NULL && routing_table_is_valid(routing_table, rreq->dest_addr)) {
        // 检查序列号是否足够新
        if (route_entry->dest_seq_num >= rreq->dest_seq_num) {
            return 0; // 有有效路由且序列号足够新，不转发
        }
    }
    
    // 需要转发
    return 1;
}

// 转发 RREQ 消息
int forward_rreq(const aodv_rreq *rreq, uint32_t local_ip, int socket) {
    if (rreq == NULL || socket <= 0) return -1;
    
    // 创建要转发的 RREQ（增加跳数）
    aodv_rreq forward_rreq = *rreq;
    forward_rreq.hop_count++;  // 增加跳数
    
    // 设置源地址为当前节点
    // 注意：这里需要根据实际网络情况设置广播地址
    uint32_t broadcast_addr = 0xFFFFFFFF; // 255.255.255.255
    
    // 发送 RREQ（广播）
    int result = aodv_socket_send(socket, &forward_rreq, sizeof(aodv_rreq), 
                                 broadcast_addr, AODV_PORT);
    
    if (result > 0) {
        printf("Forwarded RREQ (ID=%u) from %s, HopCount=%u\n",
               forward_rreq.rreq_id, 
               inet_ntoa(*(struct in_addr*)&local_ip),
               forward_rreq.hop_count);
        return 0;
    } else {
        fprintf(stderr, "Failed to forward RREQ\n");
        return -1;
    }
}

// 生成 RREP 作为对 RREQ 的响应
int generate_rrep_for_rreq(const aodv_rreq *rreq, uint32_t local_ip, 
                           aodv_routing_table *routing_table, int socket) {
    if (rreq == NULL || routing_table == NULL || socket <= 0) return -1;
    
    aodv_rrep rrep;
    uint32_t dest_seq_num;
    uint8_t hop_count;
    uint32_t lifetime = 3000; // 3秒生命周期
    
    // 情况 1：当前节点是目标节点
    if (rreq->dest_addr == local_ip) {
        dest_seq_num = 0; // 这里应该使用本地序列号
        hop_count = 0;    // 到自己是0跳
        build_rrep_packet(&rrep, 
                         local_ip,           // 目标地址（当前节点）
                         dest_seq_num,       // 目标序列号
                         rreq->orig_addr,    // 源地址
                         0,                  // 源序列号（这里简化为0）
                         hop_count,          // 跳数
                         lifetime);          // 生命周期
    }
    // 情况 2：当前节点有到目标节点的有效路由
    else {
        routing_table_entry *route_entry = routing_table_find(routing_table, rreq->dest_addr);
        if (route_entry == NULL || !routing_table_is_valid(routing_table, rreq->dest_addr)) {
            return -1; // 没有有效路由
        }
        
        dest_seq_num = route_entry->dest_seq_num;
        hop_count = route_entry->hop_count;
        build_rrep_packet(&rrep,
                         rreq->dest_addr,    // 目标地址
                         dest_seq_num,       // 目标序列号
                         rreq->orig_addr,    // 源地址
                         0,                  // 源序列号（这里简化为0）
                         hop_count,          // 跳数
                         lifetime);          // 生命周期
    }
    
    // 发送 RREP（单播到 RREQ 的源节点）
    int result = aodv_socket_send(socket, &rrep, sizeof(aodv_rrep), 
                                 rreq->orig_addr, AODV_PORT);
    
    if (result > 0) {
        printf("Generated RREP for RREQ (ID=%u) to %s\n",
               rreq->rreq_id, 
               inet_ntoa(*(struct in_addr*)&rreq->orig_addr));
        return 0;
    } else {
        fprintf(stderr, "Failed to send RREP\n");
        return -1;
    }
}

// 处理接收到的 RREQ 消息
int process_rreq_message(const aodv_rreq *rreq, uint32_t source_ip, 
                        aodv_routing_table *routing_table, 
                        rreq_id_cache *rreq_cache, uint32_t local_ip) {
    if (rreq == NULL || routing_table == NULL || rreq_cache == NULL) return -1;
    
    char src_str[INET_ADDRSTRLEN];
    char dest_str[INET_ADDRSTRLEN];
    strcpy(src_str, inet_ntoa(*(struct in_addr*)&rreq->orig_addr));
    strcpy(dest_str, inet_ntoa(*(struct in_addr*)&rreq->dest_addr));
    
    printf("Processing RREQ (ID=%u) from %s to %s, HopCount=%u\n",
           rreq->rreq_id,
           src_str,
           dest_str,
           rreq->hop_count);
    
    // 添加 RREQ ID 到缓存（防止重复处理）
    rreq_id_cache_add(rreq_cache, rreq->orig_addr, rreq->rreq_id);
    
    // 情况 1：当前节点是目标节点
    if (rreq->dest_addr == local_ip) {
        printf("This node is the destination for RREQ (ID=%u)\n", rreq->rreq_id);
        return generate_rrep_for_rreq(rreq, local_ip, routing_table, 0); // 这里 socket 参数需要外部提供
    }
    
    // 情况 2：当前节点有到目标节点的有效路由
    routing_table_entry *route_entry = routing_table_find(routing_table, rreq->dest_addr);
    if (route_entry != NULL && routing_table_is_valid(routing_table, rreq->dest_addr)) {
        if (route_entry->dest_seq_num >= rreq->dest_seq_num) {
            printf("Found valid route to destination for RREQ (ID=%u)\n", rreq->rreq_id);
            return generate_rrep_for_rreq(rreq, local_ip, routing_table, 0); // 这里 socket 参数需要外部提供
        }
    }
    
    // 情况 3：需要转发 RREQ
    if (should_forward_rreq(rreq, local_ip, routing_table, rreq_cache)) {
        printf("Forwarding RREQ (ID=%u)\n", rreq->rreq_id);
        return 0; // 转发操作需要外部 socket 支持
    }
    
    return 0;
}

// 生成并发送 RREQ 消息
int send_rreq(uint32_t dest_addr, uint32_t dest_seq_num, uint32_t local_ip, 
              int socket, aodv_routing_table *routing_table) {
    if (routing_table == NULL || socket <= 0) return -1;
    
    // 首先检查是否有到目标节点的有效路由
    routing_table_entry *route_entry = routing_table_find(routing_table, dest_addr);
    if (route_entry != NULL && routing_table_is_valid(routing_table, dest_addr)) {
        printf("Already have valid route to %s, no need to send RREQ\n",
               inet_ntoa(*(struct in_addr*)&dest_addr));
        return 0;
    }
    
    // 生成新的 RREQ
    aodv_rreq rreq;
    uint32_t rreq_id = generate_rreq_id();
    uint32_t current_time = (uint32_t)time(NULL);
    
    // 构建 RREQ 消息
    build_rreq_packet(&rreq,
                     rreq_id,           // RREQ ID
                     dest_addr,         // 目标地址
                     dest_seq_num,      // 目标序列号
                     local_ip,          // 源地址
                     0,                 // 跳数（初始为0）
                     current_time);     // 时间戳
    
    // 设置广播地址
    uint32_t broadcast_addr = 0xFFFFFFFF; // 255.255.255.255
    
    // 发送 RREQ
    int result = aodv_socket_send(socket, &rreq, sizeof(aodv_rreq), 
                                 broadcast_addr, AODV_PORT);
    
    if (result > 0) {
        printf("Sent RREQ (ID=%u) for destination %s\n",
               rreq_id, inet_ntoa(*(struct in_addr*)&dest_addr));
        return 0;
    } else {
        fprintf(stderr, "Failed to send RREQ\n");
        return -1;
    }
}